home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2009 February
/
PCWFEB09.iso
/
Software
/
Linux
/
Kubuntu 8.10
/
kubuntu-8.10-desktop-i386.iso
/
casper
/
filesystem.squashfs
/
usr
/
share
/
hplip
/
dat2drv.py
< prev
next >
Wrap
Text File
|
2008-10-13
|
25KB
|
828 lines
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Don Welch
#
__version__ = "2.1"
__title__ = 'DAT to DRV.IN converter. Also creates Foomatic XML files.'
__doc__ = "Create DRV.IN file and Foomatic XML files from MODELS.DAT data. Processes all *.in.template files in prnt/drv directory."
import os
os.putenv("HPLIP_BUILD", "1")
# Std Lib
import os.path
import sys
import getopt
import re
from xml.dom.minidom import Document, parse, parseString
from types import StringType, UnicodeType
import string
# Local
from base.g import *
from base import utils, tui, models
#from prnt import printable_areas
# Globals
errors = 0
count = 0
enc = 'utf-8'
models_dict = {}
norm_models = {} # { 'norm'd model' : ( 'model', type, has_scanner ), ... }
norm_models_keys = {}
model_dat = None
total_models = 0
sorted_category_models = {}
unsupported_models = []
pat_prod_num = re.compile("""(\d+)""", re.I)
pat_template = re.compile("""^(\s*)//\s*<%(\S+)%>""", re.I)
pat_template2 = re.compile("""^\s*<%(\S+)%>""", re.I)
USAGE = [(__doc__, "", "name", True),
("Usage: dat2drv.py [OPTIONS]", "", "summary", True),
utils.USAGE_OPTIONS,
("Verbose mode:", "-v or --verbose", "option", False),
("Quiet mode:", "-q or --quiet", "option", False),
utils.USAGE_LOGGING1, utils.USAGE_LOGGING2,
utils.USAGE_HELP,
]
def usage(typ='text'):
if typ == 'text':
utils.log_title(__title__, __version__)
utils.format_text(USAGE, typ, __title__, 'drv2xml.py', __version__)
sys.exit(0)
def _encode(v):
if isinstance(v, UnicodeType):
v = v.encode(enc)
return v
class XMLElement:
def __init__(self, doc, el):
self.doc = doc
self.el = el
def __getitem__(self, name):
a = self.el.getAttributeNode(name)
if a:
return _encode(a.value)
return None
def __setitem__(self, name, value):
self.el.setAttribute(name, _encode(value))
def __delitem__(self, name):
self.el.removeAttribute(name)
def __str__(self):
return _encode(self.doc.toprettyxml())
def toString(self):
return _encode(self.doc.toxml())
def _inst(self, el):
return XMLElement(self.doc, el)
def get(self, name, default=None):
a = self.el.getAttributeNode(name)
if a:
return _encode(a.value)
return _encode(default)
def add(self, tag, **kwargs):
el = self.doc.createElement(tag)
for k, v in kwargs.items():
el.setAttribute(k, _encode(str(v)))
return self._inst(self.el.appendChild(el))
def addText(self, data):
return self._inst(
self.el.appendChild(
self.doc.createTextNode(_encode(data))))
def addComment(self, data):
return self._inst(
self.el.appendChild(
self.doc.createComment(data)))
def getText(self, sep=" "):
rc = []
for node in self.el.childNodes:
if node.nodeType == node.TEXT_NODE:
rc.append(node.data)
return _encode(string.join(rc, sep))
def getAll(self, tag):
return map(self._inst, self.el.getElementsByTagName(tag))
class XMLDocument(XMLElement):
def __init__(self, tag=None, **kwargs):
self.doc = Document()
XMLElement.__init__(self, self.doc, self.doc)
if tag:
self.el = self.add(tag, **kwargs).el
def parse(self, d):
self.doc = self.el = parse(d)
return self
def parseString(self, d):
self.doc = self.el = parseString(_encode(d))
return self
def fixFileName(model):
if model.startswith('hp_'):
model = model.replace('hp_', 'hp-')
elif model.startswith('apollo_'):
model = model.replace('apollo_', 'apollo-')
elif not model.startswith('hp-'):
model = 'hp-' + model
return model
def categorize2(m):
is_aio = (models_dict[m]['scan-type'] != SCAN_TYPE_NONE or
models_dict[m]['copy-type'] != COPY_TYPE_NONE or
models_dict[m]['fax-type'] != FAX_TYPE_NONE)
if "deskjet" in m or \
("color" in m and "inkjet" in m) or \
m.startswith("dj") or \
m.startswith("cp"):
if is_aio:
i = MODEL_TYPE2_DESKJET_AIO
else:
i = MODEL_TYPE2_DESKJET
elif "photosmart" in m:
i = MODEL_TYPE2_PHOTOSMART
elif "officejet" in m:
i = MODEL_TYPE2_OFFICEJET
elif "psc" in m or \
"printer_scanner_copier" in m:
i = MODEL_TYPE2_PSC
elif "laserjet" in m:
if "color" in m:
i = MODEL_TYPE2_COLOR_LASERJET
else:
i = MODEL_TYPE2_LASERJET
elif "mopier" in m:
i = MODEL_TYPE2_LASERJET
elif "business" in m and \
"inkjet" in m:
i = MODEL_TYPE2_BIJ
elif "edgeline" in m:
i = MODEL_TYPE2_EDGELINE
elif "apollo" in m:
i = MODEL_TYPE2_APOLLO
else: # Other
i = MODEL_TYPE2_OTHER
return (m, i, models_dict[m])
def sort_product(x, y):
try:
_x = int(pat_prod_num.search(x).group(1))
except (TypeError, AttributeError):
_x = 0
try:
_y = int(pat_prod_num.search(y).group(1))
except (TypeError, AttributeError):
_y = 0
if not _x and not _y:
return cmp(x, y)
return cmp(_x, _y)
def sort_product2(x, y): # sort key is first element of tuple
return sort_product(x[0], y[0])
def load_models(unreleased=True):
global models_dict
global norm_models
global norm_models_keys
global model_dat
global total_models
global sorted_category_models
global unsupported_models
models_dict = model_dat.read_all_files(unreleased)
log.debug("Raw models:")
for m in models_dict:
nm = models.normalizeModelUIName(m)
models_dict[m]['norm_model'] = nm
models_dict[m]['case_models'] = []
i, case_models = 1, []
while True:
try:
cm = models.normalizeModelUIName(models_dict[m]['model%d' % i])
except KeyError:
break
case_models.append(cm)
i+= 1
if not case_models:
case_models = [nm]
models_dict[m]['case_models'] = case_models[:]
cat = categorize2(m)
models_dict[m]['category'] = cat
for c in case_models:
norm_models[c] = cat
if models_dict[m]['support-type'] == SUPPORT_TYPE_NONE:
unsupported_models.append((c, m))
norm_models_keys = norm_models.keys()
norm_models_keys.sort(lambda x, y: sort_product(x, y))
unsupported_models.sort(lambda x, y: sort_product2(x, y))
total_models = len(norm_models)
#log.info("Loaded %d models." % total_models)
def main(args):
global errors
global model_dat
line_num = 0
log.set_module("dat2drv.py")
cur_path = os.path.realpath(os.path.normpath(os.getcwd()))
dat_path = os.path.join(cur_path, 'data', 'models')
model_dat = models.ModelData(dat_path)
load_models()
verbose = False
quiet = False
try:
opts, args = getopt.getopt(args, 'd:l:ho:vq',
['logging=', 'help',
'help-rest', 'help-man',
'drv=', 'output=',
'verbose', 'quiet'])
except getopt.GetoptError, e:
log.error(e.msg)
usage()
sys.exit(0)
log_level = 'info'
if os.getenv("HPLIP_DEBUG"):
log.set_level('debug')
for o, a in opts:
if o in ('-h', '--help'):
usage()
elif o == '--help-rest':
usage('rest')
elif o == '--help-man':
usage('man')
elif o in ('-v', '--verbose'):
verbose = True
elif o in ('-q', '--quiet'):
quiet = True
elif o in ('-l', '--logging'):
log.set_level(a.lower().strip())
if not quiet:
utils.log_title(__title__, __version__)
drv_dir = os.path.join(cur_path, 'prnt', 'drv')
errors = []
warns = []
notes = []
for template_file in utils.walkFiles(drv_dir, recurse=False, abs_paths=True,
return_folders=False, pattern='*.in.template'):
basename = os.path.basename(template_file).split('.')[0]
# Output
drv_in_file = os.path.join(cur_path, 'prnt', 'drv', '%s.drv.in' % basename)
# XML output (per model)
output_path = os.path.join(cur_path, 'prnt', 'drv', 'foomatic_xml', basename)
# XML Output (master driver list)
driver_path = os.path.join(cur_path, 'prnt', 'drv', 'foomatic_xml', basename, '%s.xml' % basename)
log.info("Working on %s file..." % basename)
log.info("Input file: %s" % template_file)
log.info("Output file: %s" % drv_in_file)
log.info("Output XML directory: %s" % output_path)
log.info("Output driver XML file: %s" % driver_path)
# CREATE DRV.IN FILE
log.info("Processing %s.drv.in.template..." % basename)
tui.update_spinner()
template_classes = []
template_file_f = open(template_file, 'r')
drv_in_file_f = open(drv_in_file, 'w')
models_placement = {}
for m in models_dict:
models_placement[m] = 0
line = 0
for x in template_file_f:
if verbose:
log.info(x.strip())
line += 1
tui.update_spinner()
drv_in_file_f.write(x)
match = pat_template.match(x)
if match is not None:
matches = []
indent = match.group(1)
indent2 = ' '*(len(indent)+2)
classes = match.group(2).split(':')
tech_class = classes[0]
if tech_class not in models.TECH_CLASSES:
errors.append("(%s:line %d) Invalid tech-class (%s): %s" % (basename, line, tech_class, x.strip()))
continue
template_classes.append(tech_class)
tech_subclass = classes[1:]
ok = True
for sc in tech_subclass:
if sc not in models.TECH_SUBCLASSES:
errors.append("(%s:line %d) Invalid tech-subclass (%s): %s" % (basename, line, sc, x.strip()))
ok = False
if not ok:
continue
for m in models_dict:
if tech_class in models_dict[m]['tech-class']:
include = True
for sc in models_dict[m]['tech-subclass']:
if not sc in tech_subclass:
include = False
break
if include:
models_placement[m] += 1
matches.append(m)
if matches:
matches.sort(lambda x, y: sort_product(x, y))
for p in matches:
if verbose:
log.info("(%s) Adding section for model: %s" % (basename, p))
drv_in_file_f.write("%s{\n" % indent)
drv_in_file_f.write('%sModelName "%s Foomatic/hpijs"\n' %
(indent2, models_dict[p]['norm_model']))
if 'apollo' in p.lower():
devid = "MFG:APOLLO;MDL:%s;DES:%s;" % (p, p)
else:
devid = "MFG:HP;MDL:%s;DES:%s;" % (p, p)
drv_in_file_f.write('%sAttribute "1284DeviceID" "" "%s"\n' % (indent2, devid))
if len(models_dict[p]['tech-class']) > 1: # and 'Postscript' not in models_dict[p]['tech-class']:
drv_in_file_f.write('%sPCFileName "%s-hpijs-%s.ppd"\n' %
(indent2, fixFileName(p), models.TECH_CLASS_PDLS[tech_class]))
elif tech_class != 'Postscript':
drv_in_file_f.write('%sPCFileName "%s-hpijs.ppd"\n' % (indent2, fixFileName(p)))
else:
drv_in_file_f.write('%sPCFileName "%s-ps.ppd"\n' % (indent2, fixFileName(p)))
for c in models_dict[p]['case_models']:
drv_in_file_f.write('%sAttribute "Product" "" "%s"\n' % (indent2, c))
drv_in_file_f.write("%s}\n" % indent)
else:
errors.append("(%s:line %d) No models matched the specified classes on line: %s" % (basename, line, x.strip()))
else:
match = pat_template2.match(x)
if match is not None:
errors.append("(%s:line %d) Malformed line: %s (missing initial //)" % (basename, line, x.strip()))
template_file_f.close()
drv_in_file_f.close()
tui.cleanup_spinner()
for tc in models.TECH_CLASSES:
if tc.lower() in ('undefined', 'postscript', 'unsupported'):
continue
if tc not in template_classes:
errors.append("(%s) Section <%%%s:...%%> not found." % (basename, tc))
# OUTPUT XML FILES
if not os.path.exists(output_path):
os.makedirs(output_path)
if os.path.exists(driver_path):
os.remove(driver_path)
files_to_delete = []
for f in utils.walkFiles(output_path, recurse=True, abs_paths=True, return_folders=False, pattern='*'):
files_to_delete.append(f)
for f in files_to_delete:
os.remove(f)
driver_f = file(driver_path, 'w')
driver_doc = XMLDocument("driver", id="driver/%s" % basename)
name_node = driver_doc.add("name")
name_node.addText(basename)
url_node = driver_doc.add("url")
url_node.addText("http://hplip.sourceforge.net/")
supplier_node = driver_doc.add("supplier")
supplier_node.addText("Hewlett-Packard")
mfg_node = driver_doc.add("manufacturersupplied")
mfg_node.addText("HP|Apollo")
lic_node = driver_doc.add("license")
lic_node.addText("BSD/GPL/MIT")
driver_doc.add("freesoftware")
support_node = driver_doc.add("supportcontact", level="voluntary", url="https://launchpad.net/hplip")
support_node.addText("HPLIP Support at Launchpad.net")
shortdesc_node = driver_doc.add("shortdescription")
shortdesc_en_node = shortdesc_node.add("en")
shortdesc_en_node.addText("HP's IJS driver for most of their non-PostScript printers")
func_node = driver_doc.add("functionality")
maxresx_node = func_node.add("maxresx")
maxresx_node.addText("1200")
maxresy_node = func_node.add("maxresy")
maxresy_node.addText("1200")
func_node.add("color")
exec_node = driver_doc.add("execution")
exec_node.add("nopjl")
exec_node.add("ijs")
proto_node = exec_node.add("prototype")
proto_node.addText("gs -q -dBATCH -dPARANOIDSAFER -dQUIET -dNOPAUSE -sDEVICE=ijs -sIjsServer=hpijs%A%B%C -dIjsUseOutputFD%Z -sOutputFile=- -")
comments_node = driver_doc.add("comments")
comments_en_node = comments_node.add("en")
comments_en_node.addText("")
printers_node = driver_doc.add("printers")
for m in models_dict:
if 'apollo' in m.lower():
make = 'APOLLO'
else:
make = 'HP'
if 'apollo' in m.lower():
ieee1284 = "MFG:APOLLO;MDL:%s;DES:%s;" % (m, m)
else:
ieee1284 = "MFG:HP;MDL:%s;DES:%s;" % (m, m)
postscriptppd = ''
if 'Postscript' in models_dict[m]['tech-class']:
postscriptppd = "%s-ps.ppd" % fixFileName(m)
fixed_model = m.replace(' ', '_')
if fixed_model.startswith('hp_'):
fixed_model = fixed_model.replace('hp_', 'hp-')
elif fixed_model.startswith('apollo_'):
fixed_model = fixed_model.replace('apollo_', 'apollo-')
else:
fixed_model = 'hp-' + fixed_model
stripped_model = m
if stripped_model.startswith('hp '):
stripped_model = stripped_model.replace('hp ', '')
# Output to the per-model XML file
outputModel(m, fixed_model, stripped_model, make, postscriptppd, ieee1284, output_path, verbose)
# Output to driver master XML file
outputDriver(m, fixed_model, stripped_model, make, printers_node, verbose)
driver_f.write(str(driver_doc))
driver_f.close()
# Make sure all models ended up in drv.in file
log.info("Checking for errors...")
tui.update_spinner()
for m in models_dict:
tui.update_spinner()
tc = models_dict[m]['tech-class']
st = models_dict[m]['support-type']
if not tc or 'Undefined' in tc:
if st:
errors.append('(%s) Invalid tech-class for model %s ("Undefined" or missing)' % (basename, m))
else:
warns.append('(%s) Invalid tech-class for unsupported model %s ("Undefined" or missing)' % (basename, m))
else:
if not models_placement[m] and st and \
len(tc) == 1 and 'Postscript' not in tc:
sects = []
for tc in models_dict[m]['tech-class']:
for sc in models_dict[m]['tech-subclass']:
sects.append(sc)
errors.append("(%s) Model '%s' did not have a matching section. Needed section: <%%%s:%s%%>" %
(basename, m, tc, ':'.join(sects)))
if len(tc) == 1 and 'Postscript' in tc:
notes.append("(%s) Postscript-only model %s was not included in DRV file." % (basename, m))
tui.cleanup_spinner()
# end for
if not quiet or verbose:
if notes:
tui.header("NOTES")
for n in notes:
log.note(n)
if warns:
tui.header("WARNINGS")
for w in warns:
log.warn(w)
if errors:
tui.header("ERRORS")
for e in errors:
log.error(e)
else:
if warns:
log.warn("%d warnings" % len(warns))
if errors:
log.error("%d errors" % len(errors))
def parseDeviceID(device_id):
d= {}
x = [y.strip() for y in device_id.strip().split(';') if y]
for z in x:
y = z.split(':')
try:
d.setdefault(y[0].strip(), y[1])
except IndexError:
d.setdefault(y[0].strip(), None)
d.setdefault('MDL', '')
d.setdefault('SN', '')
if 'MODEL' in d:
d['MDL'] = d['MODEL']
del d['MODEL']
if 'SERIAL' in d:
d['SN'] = d['SERIAL']
del d['SERIAL']
elif 'SERN' in d:
d['SN'] = d['SERN']
del d['SERN']
if d['SN'].startswith('X'):
d['SN'] = ''
return d
def outputModel(model, fixed_model, stripped_model, make, postscriptppd, ieee1284, output_path, verbose=False):
global errors
global count
count += 1
## fixed_model = model.replace(' ', '_')
##
## if fixed_model.startswith('hp_'):
## fixed_model = fixed_model.replace('hp_', 'hp-')
##
## elif fixed_model.startswith('apollo_'):
## fixed_model = fixed_model.replace('apollo_', 'apollo-')
##
## else:
## fixed_model = 'hp-' + fixed_model
##
## stripped_model = model
## if stripped_model.startswith('hp '):
## stripped_model = stripped_model.replace('hp ', '')
output_filename = os.path.join(output_path, fixed_model+".xml")
if verbose:
log.info("\n\n%s:" % output_filename)
output_f = file(output_filename, 'w')
doc = XMLDocument("printer", id="printer/%s" % fixed_model)
make_node = doc.add("make")
make_node.addText(make)
model_node = doc.add("model")
model_node.addText(stripped_model)
url_node = doc.add("url")
url_node.addText("http://www.hp.com")
lang_node = doc.add("lang")
lang_node.add("pcl", level="3")
if postscriptppd:
# Postscript
ps_node = lang_node.add("postscript", level="2")
lang_node.add("pjl")
ppd_node = ps_node.add("ppd")
ppd_node.addText(postscriptppd)
charset_node = lang_node.add("charset")
charset_node.addText("us-ascii")
autodetect_node = doc.add("autodetect")
general_node = autodetect_node.add("general")
if 1:
ieee1284_node = general_node.add("ieee1284")
ieee1284_node.addText(ieee1284)
device_id = parseDeviceID(ieee1284)
mfg_node = general_node.add("manufacturer")
mfg_node.addText(device_id['MFG'])
model_node = general_node.add("model")
model_node.addText(device_id['MDL'])
desc_node = general_node.add("description")
desc_node.addText(device_id['DES'])
#cmdset_node = general_node.add("commandset")
#cmdset_node.addText("???")
driver_node = autodetect_node.add("driver")
if postscriptppd:
driver_node.addText("Postscript")
else:
driver_node.addText("hpijs")
if verbose:
log.info(str(doc))
output_f.write(str(doc))
output_f.close()
def outputDriver(m, fixed_model, stripped_model, make, printers_node, verbose):
tech_classes = models_dict[m]['tech-class']
#print tech_classes
printer_node = printers_node.add("printer")
id_node = printer_node.add("id")
id_node.addText("printer/%s" % fixed_model)
## margins_node = printer_node.add("margins")
## general_margins_node = margins_node.add("general")
## unit_node = general_margins_node.add("unit")
## unit_node.addText("in")
##
## for tc in tech_classes:
## if tc not in ('Undefined', 'Unsupported', 'PostScript'):
## try:
## margins_data = printable_areas.data[tc]
## except KeyError:
## continue
## else:
## print margins_data
## break
##<printer>
## <id>printer/HP-DeskJet_350C</id><!-- HP DeskJet 350C -->
## <functionality>
## <maxresx>600</maxresx>
## <maxresy>300</maxresy>
## </functionality>
## <ppdentry>
## *DefaultResolution: 600dpi
## </ppdentry>
## <margins>
## <general>
## <unit>in</unit>
## <relative />
## <left>0.25</left>
## <right>0.25</right>
## <top>0.125</top>
## <bottom>0.67</bottom>
## </general>
## <exception PageSize="A4">
## <left>0.135</left>
## <right>0.135</right>
## </exception>
## </margins>
## </printer>
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))